package com.health.yb.core.conf;

import cn.hutool.core.util.StrUtil;
import com.health.yb.core.exception.CommonException;
import com.health.yb.web.bean.common.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;

/**
 * 异常处理
 *
 * @author Zhanp Ping
 * @version 1.0
 * @date 2019/12/4 10:05
 */
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Response exceptionHandler(HttpServletRequest request, Exception e) throws Exception {
        String[] activeProfiles = applicationContext.getEnvironment().getActiveProfiles();
        StackTraceElement[] stackTrace = e.getStackTrace();
        //开发环境(控制台打印方法调用栈信息，定位到具体的异常代码).
        for (String profileName : activeProfiles) {
            if ("dev".equals(profileName)) {
                e.printStackTrace();
                break;
            } else {//其他环境.
                log.error("{}:{}(Line:{}),Host {} invokes url {} Exception Messages: {} ", e.getClass(), stackTrace[0].getClassName() + "." + stackTrace[0].getMethodName(), stackTrace[0].getLineNumber(), request.getRemoteHost(), request.getRequestURL(), e.getMessage());
                break;
            }
        }
        log.error(e.getMessage());
        if (e instanceof NoHandlerFoundException) {
            //404路径异常
            return new Response().failureWithCode(404);
        } else if (e instanceof BindException) {
            //validation 验证数据实体类数据异常
            BindingResult br = (BindException) e;
            List<FieldError> fieldErrors = br.getFieldErrors();
            StringBuffer sb = new StringBuffer();
            for (FieldError fieldError : fieldErrors) {
                if (StrUtil.isBlank(sb.toString())) {
                    sb.append(fieldError.getDefaultMessage());
                } else {
                    sb.append("、").append(fieldError.getDefaultMessage());
                }
            }
            String defaultMessage = sb.toString();
            return new Response().failureWithMsg(defaultMessage);
        } else if (e instanceof MethodArgumentNotValidException) {
            //验证方法单独几个参数的validation异常验证信息
            MethodArgumentNotValidException manve = (MethodArgumentNotValidException) e;
            BindingResult br = manve.getBindingResult();
            while (br.hasErrors()) {
                return new Response().failureWithMsg(br.getFieldError().getDefaultMessage());
            }
        } else if (e instanceof ConstraintViolationException) {
            //验证方法单独几个参数的validation异常验证信息
            ConstraintViolationException exs = (ConstraintViolationException) e;
            Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
            StringBuilder returnMessage = new StringBuilder();
            for (ConstraintViolation<?> item : violations) {
                if (StrUtil.isNotBlank(item.getMessage())) {
                    returnMessage.append(item.getMessage()).append("、");
                }
            }
            String substring = returnMessage.toString().substring(0, returnMessage.lastIndexOf("、"));
            return new Response().failureWithMsg(substring);
        } else if (e instanceof NullPointerException) {
            //空指针异常
            log.error("空指针异常!'" + stackTrace[0].getClassName() + "." + stackTrace[0].getMethodName() + "(Line:" + stackTrace[0].getLineNumber() + ")'");
        } else if (e instanceof CommonException) {
            return new Response().failureWithMsg(e.getMessage());
        }
        return new Response().failureWithMsg(e.getMessage());
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
